package com.mach4.gamesuite;

import android.util.Log;
//import android.view.View;
//import android.widget.Button;
import android.widget.Toast;

import com.skiller.api.listeners.SKListenerInterface;
import com.skiller.api.operations.SKApplication;
import com.skiller.api.operations.SKTurnBasedTools;
import com.skiller.api.operations.SKTurnBasedTools.eTBGameEvent;
import com.skiller.api.operations.SKTurnBasedTools.eTBGameState;
import com.skiller.api.responses.SKGameMoveResponse;
import com.skiller.api.responses.SKGameStartedResponse;
import com.skiller.api.responses.SKStatusResponse;

public class BattleshipManager
{
    public enum ePlayer 
    { 
    	NONE, 
    	OPPONENT, 
    	ME;  
    }
    public enum stateReturn // Return value for checkBoard
    {
        NORMAL,
        SUNK,
        GAMEOVER;
    }
    
	private BattleshipActivity mBoardUI;
	private String mGameId;
	private boolean mMyTurn;
	//private boolean mIsGameOwner;
	
	/** Final Battleship Variables *************************************/
	final public char EMPTY = 'E';
	final public char HIT = 'H';
	final public char MISS = 'M';
	final public char CARRIER = 'C';
	final public char BATTLESHIP = 'B';
	final public char CRUISER = 'K';
	final public char SUBMARINE = 'S';
	final public char DESTROYER = 'D';
	public boolean gameWonStatus = false;
	private char[][] attackBoard = new char[10][10];
	private char[][] defendBoard = new char[10][10];
	private boolean gameReady;
	
	private SKTurnBasedTools mTurnbasedTools;
	private SKListenerInterface<SKGameMoveResponse> mMoveListener;
	private boolean mIsBackPressed;
	
	private static BattleshipManager mInstance = new BattleshipManager();
	
	private BattleshipManager()
	{		
		mTurnbasedTools = SKApplication.getInstance().getGameManager().getTurnBasedTools();
		
		mMoveListener = new SKListenerInterface<SKGameMoveResponse>() 
		{
			@Override
			public void onResponse(SKGameMoveResponse response)
			{				
				eTBGameState gameState = response.getGameState();
				String gameId = response.getGameId();
				String payload = response.getPayload();
				
				Log.w("onResponse", "GameID: " + gameId);
				Log.w("onResponse", "Payload: " + payload);
				
				//Check if user has received opponent's ship state yet.
				if(gameReady == false)
				{
					//Update user's attack board with opponent's ship placement
					setAttack(payload);
					gameReady = true;
					
					//Send current player's ship board to opponent
					String defendBoardState = "";					
					for(int i = 0; i < 10; i++)
						for(int j = 0; j < 10; j++)
							defendBoardState = defendBoardState + defendBoard[i][j];
					
		        	mTurnbasedTools.makeMove(response.getGameId(), eTBGameEvent.GAME_EVENT_MAKING_MOVE, defendBoardState, "dd", mMoveListener);
					
				}
				else
				{
					handleOpponentMove(gameState, gameId, payload);					
				}
				
				mBoardUI.displayAttackBoard(); //Display attack board with ship placement
			}

			@Override
			public void onError(SKStatusResponse response) {
            	if (mIsBackPressed == false)
            		mBoardUI.showFinalDialog("Oops", response.getStatusMessage());
				
			}
		};
	}
	
	public static BattleshipManager getInstance()
	{
		return mInstance;
	}
	
	public void createGame()
	{
		gameReady = false;
		mTurnbasedTools.createGame(0, "Battleship", "Battleship", new SKListenerInterface<SKGameStartedResponse>() 
		{
			@Override
			public void onResponse(SKGameStartedResponse response)
			{
				Log.w("Received Start Response", "Game id: " + response.getGameId());
				handleStartResponse(response);
			}

			@Override
			public void onError(SKStatusResponse response) {
				mBoardUI.showFinalDialog("Oops", "Could not open the game. Please try again.");
			}
		}); 
	}
	
	public void joinGame(String gameId)
	{
		gameReady = false;
		mTurnbasedTools.joinGame(gameId, new SKListenerInterface<SKGameStartedResponse>() 
		{
			@Override
			public void onResponse(SKGameStartedResponse response)
			{
				Log.w("joinGame", "Joining game");
				handleStartResponse(response);
			}

			@Override
			public void onError(SKStatusResponse response) {
				mBoardUI.showFinalDialog("Oops", "Could not join the game. Please try again.");
			}
		}); 
	}
	
	private void handleStartResponse(SKGameStartedResponse response)
	{
		Log.w("Start Response", "Handling Start Response");
		
		mBoardUI.initBoard(this);
		mBoardUI.setContentView(R.layout.battleship_board);
		mGameId = response.getGameId();
		mIsBackPressed = false;
		
		String ownerName = response.getOwner().getUserName();
		String currentUserName = SKApplication.getInstance().getUserManager().getCurrentUsername();
        
		String payload = "";
		for(int i = 0; i < 10; i++)
			for(int j = 0; j < 10; j++)
				payload = payload + defendBoard[i][j];
				
		//Choose who wants to make the first move:
		//The player that will not make the first move should send ready to play event and wait for opponents move
		if (ownerName.equals(currentUserName))
        {//In our case the owner of the game will wait for guests move, so we send ready to play event and wait for the move on the listener
        	//String payload = ""; //nothing to send
        	//String payload = "Current phone is opponent"; //mBoardUI.placeShips();
			String chatline = "Chat"; //nothing to chat about
        	Log.w("handleStartResponse", "Owner");
			mTurnbasedTools.makeMove(response.getGameId(), eTBGameEvent.GAME_EVENT_READY_TO_PLAY, payload, chatline, mMoveListener);
        	        
        	//mIsGameOwner = true;
        	mMyTurn = true;
        }
        else
        {
        	//String payload = "Current phone is owne r";
        	Log.w("handleStartResponse", "User: " + currentUserName);
        	Log.w("handleStartResponse", "Opponent. Game ID: " + response.getGameId());
        	mTurnbasedTools.makeMove(response.getGameId(), eTBGameEvent.GAME_EVENT_MAKING_MOVE, payload, "dd", mMoveListener);
        	//If you are the guest of the game, start playing
        	gameReady = false;
        	//mIsGameOwner = false;
        	mMyTurn = false;
        }		
	}
	
	public char[][] getAttack()
	{
		return attackBoard;
	}
	
	public char[][] getDefend()
	{
		return defendBoard;
	}
	
	private void quitGame() 
	{
		String payload = ""; //no payload to send when exiting the game
		String chatline = ""; //nothing to chat about;
		mTurnbasedTools.makeMove(mGameId, eTBGameEvent.GAME_EVENT_QUIT_GAME, payload, chatline, null);
		mBoardUI.showFinalDialog("Game over", "");
	}
	
	private void terminatePendingGame() 
	{
		mTurnbasedTools.terminatePendingGame(new SKListenerInterface<SKStatusResponse>()
		{
			@Override
			public void onResponse(SKStatusResponse response)
			{
				//Game was terminated successfully, show some message if you want to
			}

			@Override
			public void onError(SKStatusResponse response) {
				mBoardUI.showFinalDialog("Oops", "Could not terminate the game.");
			}
		});
	}
	
	public void onBackKeyPress()
	{
		mIsBackPressed = true;
		
		if (mGameId != null)
		{//If the game is in process, quit the game
			quitGame();
		}
		else
		{//If the game was not started yet, terminate it.
			terminatePendingGame();
		}
		
		mGameId = null;
	}
	
	
	private void handleOpponentMove(eTBGameState gameState, String gameId, String payload)
	{		
		switch (gameState)
        {
            case GAME_STATE_ARE_YOU_HERE:
            	String myPayload = ""; //no payload, just tell the server you are still in game
            	String chatline = ""; //nothing to chat about
            	mTurnbasedTools.makeMove(gameId, eTBGameEvent.GAME_EVENT_STILL_HERE, myPayload, chatline, mMoveListener);
                break;

            case GAME_STATE_LOST:
            	mBoardUI.showFinalDialog("Game Over", "You Lost!");
                break;

            case GAME_STATE_TIED:
            	mBoardUI.showFinalDialog("Game Over", "It's a Tie!");
                break;

            case GAME_STATE_WON:
            	mBoardUI.showFinalDialog("Game Over", "You Won!");
                break;

            case GAME_STATE_IN_PROGRESS:
            	int posRow = Integer.parseInt(payload.substring(0, 1));
            	int posCol = Integer.parseInt(payload.substring(1, 2));            	
                handleMove(gameId, posRow, posCol, ePlayer.OPPONENT);
                break;
                
            case GAME_ERROR:
            default:
            	mBoardUI.showFinalDialog("Game Over", "An error occurred.");
            	break;
        }
	}
	
	public void handleMyMove(int posRow, int posCol)
	{
		handleMove(mGameId, posRow, posCol, ePlayer.ME);
	}
	
    private synchronized void handleMove(String gameId, final int posRow, final int posCol, final ePlayer player)
    {
    	Log.w("handleMove", "handling move");
    	
    	if (!mMyTurn && player == ePlayer.ME)
			return;
    	
    	eTBGameState gameState = updateMove(posRow, posCol, player);
    	
    	if (gameState == eTBGameState.GAME_ERROR)
    	{//If illegal move was made by the player himself do nothing
			if (player == ePlayer.OPPONENT)
			{//If illegal move was made by the opponent finish the game
				mBoardUI.showFinalDialog("Oops","Opponent made illegal move.");
			}
			
			return;
    	}
    		
    	//boolean isMoveOwner = (mIsGameOwner && player == ePlayer.ME) || (!mIsGameOwner && player == ePlayer.OPPONENT);
		//mBoardUI.drawMove(posRow, posCol, isMoveOwner);

		if (player == ePlayer.OPPONENT)
        	mMyTurn = true; 
        else if (player == ePlayer.ME)
        	mMyTurn = false;
		
    	//Check if end of game
    	String payload = ""; String chatLine="";
    	if(gameState == eTBGameState.GAME_STATE_IN_PROGRESS)
    	{
    		//Check whose move is being handled
    		if(player == ePlayer.OPPONENT)
    		{ //Handling opponent's move
    			return;
    		}
    		else if(player == ePlayer.ME)
    		{ //Handling my attack.
    			payload += Integer.toString(posRow);
    			payload += Integer.toString(posCol);
    		}
    		else
    		{
    			Log.w("BattleshipManager.handleMove", "Invalid player");
    		}
    	}    		
        
        switch (gameState)
        {
            case GAME_STATE_WON:
            	mTurnbasedTools.makeMove(gameId, eTBGameEvent.GAME_EVENT_CLAIM_WIN, payload, chatLine, mMoveListener);
                break;

            case GAME_STATE_LOST:
            	mTurnbasedTools.makeMove(gameId, eTBGameEvent.GAME_EVENT_CLAIM_LOSE, payload, chatLine, mMoveListener);
                break;

            case GAME_STATE_TIED:
            	mTurnbasedTools.makeMove(gameId, eTBGameEvent.GAME_EVENT_CLAIM_TIE, payload, chatLine, mMoveListener);
                break;

            case GAME_STATE_IN_PROGRESS:
                if (player == ePlayer.ME)
                {//this was my move, update opponent about it
                	mTurnbasedTools.makeMove(gameId, eTBGameEvent.GAME_EVENT_MAKING_MOVE, payload, chatLine, mMoveListener);
                
                	//Load board with current player's ships
                	mBoardUI.displayDefendBoard();
                }
                
                //in case this is an opponent move, we need to wait for the current player to make canvas move
                break;
                
             default: break;
        }
    }
    
    private eTBGameState updateMove(int aRowPos, int aColPos, ePlayer aPlayer)
    {
        char target;
        if(aPlayer == ePlayer.ME)
        {
            target = attackBoard[aRowPos][aColPos]; //Need to know what was here before the hit
            switch(target)
            {
            case HIT:
            case MISS:
                break;
            case EMPTY:
                attackBoard[aRowPos][aColPos] = MISS;
                break;
            default:
                attackBoard[aRowPos][aColPos] = HIT;
                stateReturn state = checkBoard(target,attackBoard);
                if( state == stateReturn.GAMEOVER )
                    return eTBGameState.GAME_STATE_WON;
                else if( state == stateReturn.SUNK )
                {
                    //Output ship sunk message
                    Toast toast = Toast.makeText(mBoardUI, "You sunk a ship!", Toast.LENGTH_SHORT);
                    toast.show();
                }
                break;
            }
        }
        else
        {
            target = defendBoard[aRowPos][aColPos]; //Need to know what was here before the hit
            switch(target)
            {
            case HIT: case MISS: break;
            case EMPTY:
                defendBoard[aRowPos][aColPos] = MISS;
                break;
            default:
                defendBoard[aRowPos][aColPos] = HIT;
                stateReturn state = checkBoard(target,defendBoard);
                if( state == stateReturn.GAMEOVER )
                    return eTBGameState.GAME_STATE_LOST;
                else if( state == stateReturn.SUNK )
                {
                    //Output ship sunk message
                    Toast toast = Toast.makeText(mBoardUI, "Your ship was sunk!", Toast.LENGTH_SHORT);
                    toast.show();
                }
                break;
            }
        }        
        return eTBGameState.GAME_STATE_IN_PROGRESS;
    }
    
    private stateReturn checkBoard(char theShip, char[][] theBoard)
    {
    	boolean noShips = true; //True until we find a ship
    	for(int i = 0; i < 10; i++)
    	{
			for(int j = 0; j < 10; j++)
			{
			    switch(theBoard[i][j])
			    {
			    case EMPTY: case MISS: case HIT: break;
			    default:
			        noShips = false;
			        if(theBoard[i][j] == theShip)
			            return stateReturn.NORMAL;
			        break;
			    }
			}
    	}
    	return(noShips?stateReturn.GAMEOVER:stateReturn.SUNK);
    }
    
    public void setBoard(String boardState)
    {
    	for(int i = 0; i < 100; i++)
    	{
    		defendBoard[i / 10][i % 10] = boardState.charAt(i);
    	}
    }
    
    public void setAttack(String boardState)
    {
    	for(int i = 0; i < 100; i++)
    		attackBoard[i/10][i%10] = boardState.charAt(i);
    }
	
	public void setBoardUI(BattleshipActivity context)
	{
		this.mBoardUI = context;
	}
}
